/*
Copyright (c) 2006 - 2008  Universitaet Osnabrueck, virtUOS
Authors: Markus Ketterl, Johannes Emden, Nils Schuhmacher, Andreas Rickling

This file is part of virtPresenter.

virtPresenter is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

virtPresenter is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with virtPresenter.  If not, see <http://www.gnu.org/licenses/>.
*/

package virtPresenter.model
{
	import mx.collections.ArrayCollection;
	
	/**
	 * Class provides searching text in the lectures 
	 */
	public class SearchProvider
	{

		private static var instance:SearchProvider;
		
		private var model : virtPresenterLocator = virtPresenterLocator.getInstance();
		
		private var xmlParsers:ArrayCollection=new ArrayCollection();
		
		/**
		 * Constructor of SearchProvider. 
		 */	
		public function SearchProvider()
		{	
			if (instance != null)
        	{
        		throw new Error("SearchProvider is supposed to be singleton. Use getInstance() to fetch an instance properly.");	
         	}
     
         	if(model.lectures==null || model.lectures.length==0)
			{
				throw new Error("SearchProvider depends on the lecturerecordings.xml which is empty.");			
			}
					
			for(var i:int = 0; i<model.lectures.length; i++)
   			{
   				var lectureTitle:String = model.lectures[i].valueOf().title;
				var lectureSource:String = model.lectures[i].valueOf().source; 
				var tmpXMLParser:AdvancedXMLParser = new AdvancedXMLParser(lectureSource,lectureTitle);
				
				//Cairngormevent das sowas wie ParseAllXMLFiles macht
				//var tmpXMLParser:XMLParser=model.xmlParser;
				
				this.xmlParsers.addItem(tmpXMLParser);				
   			}
		}
		
		/**
		 * Method instanciates a new SearchProvider if no one is instanciated yet.
		 * Otherwise it delivers the existing SearchProvider. Method assures
		 * the SeaechProvider is Singleton.
		 * 
		 * @return SearchProvider 
		 */
		public static function getInstance():SearchProvider 
        {
           if (instance == null)
               instance = new SearchProvider();
           return instance;
        }
		
		/**
		 * Method searches for the given word and delivers the result of the search
		 * as a string that can be displayed in the flex tree component.
		 * 
		 * @parameter word String that is searched for
		 * 
		 * @return String  String that can be displayed in flex's tree component.
		 *
		 */
		public function search(word:String, all:Boolean, opt1:Boolean, opt2:Boolean):String
		{
			var root:TreeListItem = new TreeListItem();
			root.label="Nothing could be found";	
			var lastAppointment:TreeListItem = new TreeListItem();
			for(var i:int = 0; i<xmlParsers.length; i++)
   			{
   				// you can only search through ready AdvancedXMLParsers
   				if(xmlParsers[i].isReady())
   				{   
   					var lectureSource:String = xmlParsers[i].lectureSource;
	   				var lectureTitle:String = xmlParsers[i].lectureTitle;
	   				trace("SearchProvider. LectureTitle: "+lectureTitle);

					if(lastAppointment.appointment!=lectureSource)
 					{
 						if(lastAppointment.size!=0)	
 							root.addChild(lastAppointment);
 						lastAppointment = new TreeListItem();
 						lastAppointment.appointment=lectureSource;
 						//lastAppointment.slideID=slideID;
 						lastAppointment.time=0;
 						lastAppointment.label=lectureTitle;
 					}
					
					var lastSlide:TreeListItem = new TreeListItem();	
		 			
		 			var timeSteps:Array=xmlParsers[i].getTimeSteps();
		 			for(var j:int=0; j<timeSteps.length;j++)
		 			{
		 				var tmpTimeStep:TimeStep = timeSteps[j];
		 				var slideID:int = tmpTimeStep.getID();
		 				var text:String = tmpTimeStep.getTextOnSlide();	
						var result:String = linearSearch(text,word);
							
		 				if(result!=null)
		 				{
		 					if(lastSlide.getID()!= slideID)
		 					{
		 						if(lastSlide.label!="")
		 							lastAppointment.addChild(lastSlide);
		 						lastSlide = new TreeListItem();
		 						lastSlide.appointment=lectureSource;
		 						lastSlide.slideID=slideID;
		 						lastSlide.time=tmpTimeStep.getTime();
		 						lastSlide.label="Folie "+slideID+": "+tmpTimeStep.getTitle();
		 					}
		 					
		 					
		 					var stepNode:TreeListItem = new TreeListItem();
		 					
		 					stepNode.appointment=lectureSource;
							stepNode.time=tmpTimeStep.getTime();
		 					stepNode.label="..."+result+"...";
		 					
		 					lastSlide.addChild(stepNode);		 					
		 				}
		 			}		 			
		 		
			    }
			    if(lastSlide.label!="")
			  		lastAppointment.addChild(lastSlide);  
		    }
		    
		    if(lastAppointment.size!=0)	
		    {
		   		root.addChild(lastAppointment);
		   	}
		  	    			
			return root.toString();
		}
		
		
		private function linearSearch(fullText:String, word:String):String
		{	
			var CHARACTERS:int=25;
			var pos:int = 0;
			
			
			if(fullText==null || word==null || word=="")
				return null;
			// Make everything lower case
			var lowerFullText:String = fullText.toLowerCase();
			var lowerWord:String = word.toLowerCase();
			
			for(var i:int=0;i<lowerFullText.length;i++)
			{
				if(pos==lowerWord.length)
				{
					// Create Label String
					var start:int = i-CHARACTERS;
					if(start<0)start=0;
					
					var end:int = i+CHARACTERS;
					if(end>fullText.length) end=fullText.length;
					
					// Use normale Text for Label
					return fullText.substring(start,end);
					
				}
				if(lowerFullText.charAt(i)==lowerWord.charAt(pos))
				{
					pos++;
				}	
				else
				{
					if(pos!=0)i-- // Falls zwei gleiche Buchstaben hintereinander
					pos=0;
				}
				
			}	
			return null;		
		}	
	}
}